package com.whmskj.xjlhsc.mobie.personnelFile.controller;

import com.github.pagehelper.PageHelper;
import com.whmskj.xjlhbc.core.AjaxResult;
import com.whmskj.xjlhsc.mobie.personnelFile.dto.LeaveApplicationDetailDTO;
import com.whmskj.xjlhsc.mobie.personnelFile.service.LeaveApplicationService;
import com.whmskj.xjlhsc.mobie.personnelFile.dto.LeaveApplicationListDTO;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import cn.dev33.satoken.stp.StpUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/mobile/personnel/leave")
@RequiredArgsConstructor
@Api(tags = "移动端-人员档案-请假")
public class LeaveApplicationController {

    private final LeaveApplicationService service;

    // 请假类型
    @GetMapping("/types")
    @ApiOperation("请假类型列表")
    public AjaxResult types() {
        return AjaxResult.success(service.leaveTypes());
    }

    // 合并接口：我已处理（result=approved/rejected）
    @PostMapping("/handled-by-me")
    @ApiOperation("我已处理的请假单列表（POST JSON：result=approved|rejected）")
    public AjaxResult listHandledByMe(@RequestBody(required = false) Map<String, Object> body) {
        String userId = StpUtil.getLoginIdAsString();
        Map<String, Object> emp = service.currentEmployeeProfileByUserId(userId);
        if (emp == null) {
            return AjaxResult.error("未找到当前登录人的员工档案");
        }
        Integer myId = ((Number) emp.get("id")).intValue();

        if (body == null) body = new HashMap<>();
        String result = body.get("result") == null ? null : String.valueOf(body.get("result"));
        String employeeName = body.get("employeeName") == null ? null : String.valueOf(body.get("employeeName"));
        // 仅按“年月日”筛选：将开始设为00:00:00，结束设为23:59:59
        LocalDateTime startFrom = parseDateOnly(String.valueOf(body.getOrDefault("startFrom", "")), false);
        LocalDateTime endTo = parseDateOnly(String.valueOf(body.getOrDefault("endTo", "")), true);
        Integer pageNum = asIntOrDefault(body.get("pageNum"), 1);
        Integer pageSize = asIntOrDefault(body.get("pageSize"), 10);
        int pn = pageNum == null ? 1 : pageNum;
        int ps = pageSize == null ? 10 : pageSize;

        // 默认盘存月
        if (startFrom == null && endTo == null) {
            LocalDate today = LocalDate.now();
            LocalDate startDate, endDateM;
            if (today.getDayOfMonth() >= 20) {
                startDate = today.withDayOfMonth(20);
                LocalDate next = today.plusMonths(1);
                endDateM = next.withDayOfMonth(Math.min(21, next.lengthOfMonth()));
            } else {
                LocalDate prev = today.minusMonths(1);
                startDate = prev.withDayOfMonth(20);
                endDateM = today.withDayOfMonth(Math.min(21, today.lengthOfMonth()));
            }
            startFrom = startDate.atStartOfDay();
            endTo = endDateM.atTime(23, 59, 59);
        }

        PageHelper.startPage(pn, ps);
        List<LeaveApplicationListDTO> list = service.listHandledByMe(myId, result, employeeName, startFrom, endTo);
        com.github.pagehelper.PageInfo<LeaveApplicationListDTO> pageInfo = new com.github.pagehelper.PageInfo<>(list);

        Map<String, Object> data = new HashMap<>();
        data.put("total", pageInfo.getTotal());
        data.put("results", pageInfo.getList());
        // inventory month (盘存月) period info
        java.time.format.DateTimeFormatter df = java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd");
        Map<String, Object> inventoryMonth = new HashMap<>();
        if (startFrom != null) inventoryMonth.put("startDate", startFrom.toLocalDate().format(df));
        if (endTo != null) inventoryMonth.put("endDate", endTo.toLocalDate().format(df));
        data.put("inventoryMonth", inventoryMonth);
        return AjaxResult.success(data);
    }

    // 员工搜索（用于选择器）

    /**
     * 暂不需要
     *
     * @param keyword
     * @param limit
     * @return
     */
    @GetMapping("/employees")
    @ApiOperation("员工搜索（选择器）")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "keyword", value = "关键字（姓名/工号）", required = false, paramType = "query"),
            @ApiImplicitParam(name = "limit", value = "返回条数", required = false, paramType = "query", dataType = "int", defaultValue = "20")
    })
    public AjaxResult searchEmployees(@RequestParam(required = false) String keyword,
                                      @RequestParam(required = false, defaultValue = "20") Integer limit) {
        return AjaxResult.success(service.searchEmployees(keyword, limit));

    }


    // 当前登录人档案（用于新增页面自动填充）
    @GetMapping("/me")
    @ApiOperation("当前登录人档案信息")
    public AjaxResult currentEmployee() {
        String memberId = StpUtil.getLoginIdAsString();
        Map<String, Object> emp = service.currentEmployeeProfileByUserId(memberId);
        if (emp == null) {
            return AjaxResult.error("未找到当前登录人的员工档案");
        }
        Map<String, Object> result = new HashMap<>();
        result.put("id", emp.get("id"));
        result.put("code", emp.get("code"));
        result.put("name", emp.get("name"));
        result.put("sector", emp.get("sector"));
        result.put("positions", emp.get("positions"));
        result.put("typeOfWork", emp.get("typeOfWork"));
        return AjaxResult.success(result);
    }

    // 新增：保存/提交（submit=true 提交；false 保存草稿）
    @PostMapping("/save")
    @ApiOperation("新建请假（保存或提交）- 日期格式：yyyy-MM-dd")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "submit", value = "true=提交；false=保存草稿", required = false, paramType = "query", dataType = "boolean", defaultValue = "false")
    })
    public AjaxResult create(@RequestParam(required = false, defaultValue = "false") boolean submit,
                             @RequestBody Map<String, Object> body) {
        String userId = StpUtil.getLoginIdAsString();
        Map<String, Object> emp = service.currentEmployeeProfileByUserId(userId);
        if (emp == null) {
            return AjaxResult.error("未找到当前登录人的员工档案");
        }
        // 覆盖员工信息，防止越权
        body.put("employee_id", emp.get("id"));
        body.put("employeeCode", emp.getOrDefault("code", ""));
        body.put("employeeName", emp.get("name"));
        body.put("employeeDept", emp.getOrDefault("sector", ""));
        body.put("employeePosition", emp.getOrDefault("positions", ""));
        body.put("employeeTypeOfWork", emp.getOrDefault("typeOfWork", ""));
        // 只有在提交时才设置申请时间，保存草稿时不设置
        if (submit) {
            body.put("application_time", java.time.LocalDateTime.now().format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        }

        int id = service.create(body, submit);
        return AjaxResult.success(id);
    }

    // 更新草稿
    @PutMapping("/{id}")
    @ApiOperation("更新草稿 - 日期格式：yyyy-MM-dd")
    public AjaxResult updateDraft(@ApiParam(value = "请假单ID", required = true) @PathVariable Integer id,
                                  @RequestBody Map<String, Object> body) {
        return AjaxResult.success(service.updateDraft(id, body));
    }

    // 提交（进入审核流）
    @PostMapping("/{id}/submit")
    @ApiOperation("提交草稿进入审核")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id", value = "请假单ID", required = true, paramType = "path", dataType = "int")
    })
    public AjaxResult submit(@PathVariable Integer id) {
        return AjaxResult.success(service.submit(id, null, null));
    }

    // 撤销
    @PostMapping("/{id}/cancel")
    @ApiOperation("撤销申请")
    public AjaxResult cancel(@ApiParam(value = "请假单ID", required = true) @PathVariable Integer id,
                             @ApiParam(value = "撤销原因", required = false) @RequestParam(required = false) String cancelReason) {
        return AjaxResult.success(service.cancel(id, cancelReason));
    }


    // 列表（分页，POST + JSON 入参）
    @PostMapping
    @ApiOperation("请假列表-分页查询（POST JSON）")
    public AjaxResult list(@RequestBody(required = false) Map<String, Object> body) {
        if (body == null) body = new HashMap<>();
        Integer employeeId = asInt(body.get("employeeId"));
        String employeeName = body.get("employeeName") == null ? null : String.valueOf(body.get("employeeName"));
        String status = body.get("status") == null ? null : String.valueOf(body.get("status"));
        LocalDateTime startFrom = parseDateOnly(String.valueOf(body.getOrDefault("startFrom", "")), false);
        LocalDateTime endTo = parseDateOnly(String.valueOf(body.getOrDefault("endTo", "")), true);
        Integer pageNum = asIntOrDefault(body.get("pageNum"), 1);
        Integer pageSize = asIntOrDefault(body.get("pageSize"), 10);
        // 默认时间范围：根据当前日期判断所属盘存月（20日至次月21日；若当前日<20则取上月20日至本月21日）
        if (startFrom == null && endTo == null) {
            java.time.LocalDate today = java.time.LocalDate.now();
            java.time.LocalDate startDate;
            java.time.LocalDate endDate;
            if (today.getDayOfMonth() >= 20) {
                startDate = today.withDayOfMonth(20);
                java.time.LocalDate nextMonth = today.plusMonths(1);
                endDate = nextMonth.withDayOfMonth(Math.min(21, nextMonth.lengthOfMonth()));
            } else {
                java.time.LocalDate prevMonth = today.minusMonths(1);
                startDate = prevMonth.withDayOfMonth(20);
                endDate = today.withDayOfMonth(Math.min(21, today.lengthOfMonth()));
            }
            startFrom = startDate.atStartOfDay();
            endTo = endDate.atTime(23, 59, 59);
        }

        PageHelper.startPage(pageNum, pageSize);
        List<LeaveApplicationListDTO> list = service.list(employeeId, employeeName, status, startFrom, endTo);
        com.github.pagehelper.PageInfo<LeaveApplicationListDTO> pageInfo = new com.github.pagehelper.PageInfo<>(list);
        Map<String, Object> data = new HashMap<>();
        data.put("results", pageInfo.getList());
        // gender summary
        Map<String, Object> genderSummary = service.listGenderSummary(employeeId, employeeName, status, startFrom, endTo);
        data.put("genderSummary", genderSummary);
        // inventory month (盘存月) period info
        java.time.format.DateTimeFormatter df = java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd");
        Map<String, Object> inventoryMonth = new HashMap<>();
        if (startFrom != null) inventoryMonth.put("startDate", startFrom.toLocalDate().format(df));
        if (endTo != null) inventoryMonth.put("endDate", endTo.toLocalDate().format(df));
        data.put("inventoryMonth", inventoryMonth);
        return AjaxResult.success(data);
    }

    @PostMapping("/mine")
    @ApiOperation("请假申请列表-仅查询本人")
    public AjaxResult listMine(@RequestBody(required = false) Map<String, Object> body) {
        String userId = StpUtil.getLoginIdAsString();
        Map<String, Object> emp = service.currentEmployeeProfileByUserId(userId);
        Integer myId = emp == null ? null : ((Number) emp.get("id")).intValue();

        if (body == null) body = new HashMap<>();
        String employeeName = body.get("employeeName") == null ? null : String.valueOf(body.get("employeeName"));
        String status = body.get("status") == null ? null : String.valueOf(body.get("status"));
        LocalDateTime startFrom = parseDateOnly(String.valueOf(body.getOrDefault("startFrom", "")), false);
        LocalDateTime endTo = parseDateOnly(String.valueOf(body.getOrDefault("endTo", "")), true);
        int pageNum = asIntOrDefault(body.get("pageNum"), 1);
        int pageSize = asIntOrDefault(body.get("pageSize"), 10);

        if (startFrom == null && endTo == null) {
            LocalDate today = LocalDate.now();
            LocalDate startDate, endDate;
            if (today.getDayOfMonth() >= 20) {
                startDate = today.withDayOfMonth(20);
                LocalDate next = today.plusMonths(1);
                endDate = next.withDayOfMonth(Math.min(21, next.lengthOfMonth()));
            } else {
                LocalDate prev = today.minusMonths(1);
                startDate = prev.withDayOfMonth(20);
                endDate = today.withDayOfMonth(Math.min(21, today.lengthOfMonth()));
            }
            startFrom = startDate.atStartOfDay();
            endTo = endDate.atTime(23, 59, 59);
        }

        PageHelper.startPage(pageNum, pageSize);
        List<LeaveApplicationListDTO> list = service.listMine(myId, employeeName, status, startFrom, endTo);
        com.github.pagehelper.PageInfo<LeaveApplicationListDTO> pageInfo = new com.github.pagehelper.PageInfo<>(list);
        Map<String, Object> data = new HashMap<>();
        data.put("total", pageInfo.getTotal());
        data.put("results", pageInfo.getList());
        // inventory month (盘存月)
        java.time.format.DateTimeFormatter df2 = java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd");
        Map<String, Object> inventoryMonth2 = new HashMap<>();
        if (startFrom != null) inventoryMonth2.put("startDate", startFrom.toLocalDate().format(df2));
        if (endTo != null) inventoryMonth2.put("endDate", endTo.toLocalDate().format(df2));
        data.put("inventoryMonth", inventoryMonth2);
        return AjaxResult.success(data);
    }

    @PostMapping("/pending")
    @ApiOperation("请假列表-待我审批（当前节点）")
    public AjaxResult listPendingForApprover(@RequestBody(required = false) Map<String, Object> body) {
        String userId = StpUtil.getLoginIdAsString();
        Map<String, Object> emp = service.currentEmployeeProfileByUserId(userId);
        Integer myId = emp == null ? null : ((Number) emp.get("id")).intValue();

        if (body == null) body = new HashMap<>();
        String employeeName = body.get("employeeName") == null ? null : String.valueOf(body.get("employeeName"));
        LocalDateTime startFrom = parseDateOnly(String.valueOf(body.getOrDefault("startFrom", "")), false);
        LocalDateTime endTo = parseDateOnly(String.valueOf(body.getOrDefault("endTo", "")), true);
        int pageNum = asIntOrDefault(body.get("pageNum"), 1);
        int pageSize = asIntOrDefault(body.get("pageSize"), 10);

        // 默认盘存月
        if (startFrom == null && endTo == null) {
            LocalDate today = LocalDate.now();
            LocalDate startDate, endDateM;
            if (today.getDayOfMonth() >= 20) {
                startDate = today.withDayOfMonth(20);
                LocalDate next = today.plusMonths(1);
                endDateM = next.withDayOfMonth(Math.min(21, next.lengthOfMonth()));
            } else {
                LocalDate prev = today.minusMonths(1);
                startDate = prev.withDayOfMonth(20);
                endDateM = today.withDayOfMonth(Math.min(21, today.lengthOfMonth()));
            }
            startFrom = startDate.atStartOfDay();
            endTo = endDateM.atTime(23, 59, 59);
        }

        PageHelper.startPage(pageNum, pageSize);
        List<LeaveApplicationListDTO> list = service.listPendingForApprover(myId, employeeName, startFrom, endTo);
        com.github.pagehelper.PageInfo<LeaveApplicationListDTO> pageInfo = new com.github.pagehelper.PageInfo<>(list);

        Map<String, Object> data = new HashMap<>();
        data.put("total", pageInfo.getTotal());
        data.put("results", pageInfo.getList());
        // inventory month (盘存月)
        java.time.format.DateTimeFormatter df3 = java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd");
        Map<String, Object> inventoryMonth3 = new HashMap<>();
        if (startFrom != null) inventoryMonth3.put("startDate", startFrom.toLocalDate().format(df3));
        if (endTo != null) inventoryMonth3.put("endDate", endTo.toLocalDate().format(df3));
        data.put("inventoryMonth", inventoryMonth3);
        return AjaxResult.success(data);
    }


    // 审批通过
    @PostMapping("/{id}/approve")
    @ApiOperation("审批通过")
    public AjaxResult approve(@ApiParam(value = "请假单ID", required = true) @PathVariable Integer id) {
        String userId = StpUtil.getLoginIdAsString();
        Map<String, Object> emp = service.currentEmployeeProfileByUserId(userId);
        if (emp == null) {
            return AjaxResult.error("未找到当前登录人的员工档案");
        }
        Integer approverId = ((Number) emp.get("id")).intValue();
        String approverName = (String) emp.get("name");
        return AjaxResult.success(service.approve(id, approverId, approverName));
    }


    // 驳回（JSON 传参：{id, reason}）
    @PostMapping("/reject")
    @ApiOperation("驳回申请（JSON：{id, reason}）")
    public AjaxResult rejectJson(@RequestBody Map<String, Object> body) {
        if (body == null) body = new HashMap<>();
        Integer id = asInt(body.get("id"));
        String reason = body.get("reason") == null ? null : String.valueOf(body.get("reason")).trim();
        if (id == null) {
            return AjaxResult.error("参数 id 必填");
        }
        if (reason == null || reason.isEmpty()) {
            return AjaxResult.error("参数 reason 必填");
        }

        String userId = StpUtil.getLoginIdAsString();
        Map<String, Object> emp = service.currentEmployeeProfileByUserId(userId);
        if (emp == null) {
            return AjaxResult.error("未找到当前登录人的员工档案");
        }
        Integer approverId = ((Number) emp.get("id")).intValue();
        String approverName = (String) emp.get("name");
        return AjaxResult.success(service.reject(id, approverId, approverName, reason));
    }

    // 详情
    @GetMapping("/{id}")
    @ApiOperation("请假详情")
    public AjaxResult detail(@PathVariable Integer id) {
        LeaveApplicationDetailDTO dto = service.detail(id);
        return AjaxResult.success(dto);
    }


    private static Integer asInt(Object o) {
        if (o == null) return null;
        if (o instanceof Number) return ((Number) o).intValue();
        String s = String.valueOf(o).trim();
        if (s.isEmpty()) return null;
        return Integer.valueOf(s);
    }

    private static Integer asIntOrDefault(Object o, int def) {
        Integer v = asInt(o);
        return v == null ? def : v;
    }

    private static LocalDateTime parseDateTime(String s) {
        if (s == null) return null;
        s = s.trim();
        if (s.isEmpty()) return null;
        try {
            // 只支持 "yyyy-MM-dd HH:mm:ss" 格式
            java.time.format.DateTimeFormatter f = java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            return LocalDateTime.parse(s, f);
        } catch (Exception e) {
            throw new IllegalArgumentException("日期时间格式错误，请使用 yyyy-MM-dd HH:mm:ss");
        }
    }

    // 仅日期解析：yyyy-MM-dd，endOfDay=true 则设置为 23:59:59，否则 00:00:00
    private static LocalDateTime parseDateOnly(String s, boolean endOfDay) {
        if (s == null) return null;
        s = s.trim();
        if (s.isEmpty()) return null;
        try {
            java.time.LocalDate d = java.time.LocalDate.parse(s, java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd"));
            return endOfDay ? d.atTime(23, 59, 59) : d.atStartOfDay();
        } catch (Exception ignore) {
            // 如果传了老格式（带时分秒），回退到原解析
            return parseDateTime(s);
        }
    }


}

